////////////////////////////////////////////////////////////////////////////////
// Auteur	: Maxime Vanier et Patrick Losier
// date		: 04/03/2013
//
// description : Classe qui roule les algorithmes
///////////////////////////////////////////////////////////////////////////////	
#include <iostream>
#include <fstream>

#include "Executor.h"
#include "Algorithmes.h"
#include "Resultat.h"
#include "Timer.h"
#include "BTS.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int Executor::rapportCourant_ = 0;

Executor::Executor(std::vector<std::string>& echantillons)
	: vorace_(false)
	, dynamique_(false)
	, branchAndBound_(false)
{
	nomEchantillons_ = echantillons;
}

Executor::~Executor()
{
	std::vector<Resultat*>::iterator itResult = resultats_.begin();
	for (itResult ; itResult != resultats_.end() ; itResult++)
	{
		delete (*itResult);
	}

	std::vector<Algo*>::iterator itAlgo = algoToUse_.begin();
	for (itAlgo ; itAlgo != algoToUse_.end() ; itAlgo++)
	{
		delete (*itAlgo);
	}

	clearVilleCourante();
}

void Executor::RunAll()
{
	// Ajout des algos a rouler


	std::vector<std::string>::iterator itFile = nomEchantillons_.begin();
	int numSerie = 0;
	for (itFile ; itFile != nomEchantillons_.end() ; itFile++)
	{
		if (!extraireInfo(*itFile))
		{
			continue;
		}
		printf("ECHANTILLON : %i, TAILLE : %i, CAPACITE : %i\n", numSerie+1, villeCourante_.size(), capaciteCourante_);

		std::vector<Algo*>::iterator itAlgo = algoToUse_.begin();
		for (itAlgo ; itAlgo != algoToUse_.end() ; itAlgo++)
		{
			Resultat* result = new Resultat();
			Timer timer;
			(*itAlgo)->setTimeout(300000); // 5 min

			std::vector<int> solution;
			

			printf("   ALGO %s", (*itAlgo)->getID().c_str());

			timer.start();
			if ( (*itAlgo)->execute(villeCourante_, capaciteCourante_, solution) == -1)
			{
				result->signalError();
				printf("   \tALGO FAILED\n");
			}
			timer.stop();

			int valeur = (*itAlgo)->getSolution();

			result->setSize(villeCourante_.size());
			result->setTime(timer.getElapsedTimeInMilliSec());
			result->setValeurMax(valeur);
			result->setCapaciteCentrale(capaciteCourante_);
			result->setNumSerie(numSerie);
			result->setAlgo((*itAlgo)->getID());

			printf("    \ttemps : %f ms\t%i\n", timer.getElapsedTimeInMilliSec(), valeur);

			resultats_.push_back(result);

		}

		numSerie++;
	}

	printf(" _________________________________________________\n");
	printf("|                                                 |\n");
	printf("     VILLES TAILLE %i CAPACITE %i TERMINEES      \n", villeCourante_.size(), capaciteCourante_);
	printf("|_________________________________________________|\n");
}

void Executor::clearVilleCourante()
{
	if (villeCourante_.empty())
		return;

	std::map<int, BTS*>::iterator itBTS = villeCourante_.begin();
	for (itBTS ; itBTS != villeCourante_.end() ; itBTS++)
	{
		delete itBTS->second;
	}

	villeCourante_.clear();

	capaciteCourante_ = 0;
}

void Executor::printCSV()
{
	// Imprime les resultats dans un fichier csv
	printf("PRODUCTION RAPPORT\n");
	std::ofstream CSVReport;

	char tempString[50];
	sprintf(tempString, "Rapport_dexecution_%i_%i.csv", villeCourante_.size(), ++rapportCourant_);
	CSVReport.open (tempString);
	CSVReport << "Index Serie, Nb BTS, Capacite, valeur, Temps (ms), Algorithme" << std::endl;

	std::vector<Resultat*>::iterator itRes = resultats_.begin();
	for (itRes ; itRes != resultats_.end() ; itRes++)
	{
		CSVReport << (*itRes)->print() << std::endl;
	}
	CSVReport.close();
}

bool Executor::extraireInfo(std::string& file)
{
	clearVilleCourante();

	std::string line;
	std::vector<int> tempList;
	std::ifstream myfile (file.c_str());
	if (myfile.is_open())
	{
		if ( myfile.good() )
		{
			// capture du nombre de BTS
			getline (myfile,line);
			int nbBTS = atoi(line.c_str());

			// Extraction des BTS
			for (int i = 0 ; i < nbBTS ; i++)
			{
				std::string strBTS;
				getline (myfile,strBTS);
				BTS* tempBTS = extractBTS(strBTS);

				if (tempBTS)
				{
					villeCourante_.insert(std::pair<int, BTS*>(tempBTS->getIndex(), tempBTS));
				}
			}

			// Capture de la capacite
			getline (myfile,line);
			capaciteCourante_ = atoi(line.c_str());
			
		}
		myfile.close();
	}
	else
	{
		return false;
	}

	return true;

}

BTS* Executor::extractBTS(std::string& strBTS)
{
	if (strBTS.empty())
		return NULL;

	char* sample = (char*)strBTS.c_str();
	char* tok;

	tok = strtok(sample, " ");
	int index = atoi(tok);

	tok = strtok(NULL, " ");
	int revenu = atoi(tok);

	tok = strtok(NULL, " ");
	int abonnes = atoi(tok);

	BTS* temp = new BTS(index, revenu, abonnes);

	return temp;

}

void Executor::setVorace(bool value) 
{ 
	vorace_ = value;
	if (value)
	{
	  algoToUse_.push_back(new AlgoVorace());
	}
}

void Executor::setDynamique(bool value)
{ 
	dynamique_ = value;
	if (value)
	{
	  algoToUse_.push_back(new AlgoDynamique());
	}
}

void Executor::setBranchAndBound(bool value) 
{ 
	branchAndBound_ = value; 
	if (value)
	{
	  algoToUse_.push_back(new AlgoBranchAndBound());
	}
}